---
title: 動態型別系統對比
description: 深入理解 Python 和 JavaScript 動態型別系統的差異，掌握型別轉換規則、真值判斷和型別檢查方法。
---

# 動態型別系統對比

Python 和 JavaScript 都是動態型別語言，但它們在型別處理上有顯著差異。Python 是強型別動態語言，而 JavaScript 是弱型別動態語言。本模組將幫助你理解這些差異，避免常見的型別相關陷阱。

## 型別系統基礎概念

### 強型別 vs 弱型別

<PythonEditor title="型別系統差異" compare={true}>
```python !! py
# Python：強型別動態語言
# 不允許隱式型別轉換，型別檢查嚴格

# 基本型別
number = 42
text = "Hello"
flag = True
empty = None

print(f"數字型別: {type(number)}")
print(f"字串型別: {type(text)}")
print(f"布林型別: {type(flag)}")
print(f"空值型別: {type(empty)}")

# 嚴格的型別檢查
try:
    result = "5" + 3  # 錯誤：不能將字串和數字相加
except TypeError as e:
    print(f"型別錯誤: {e}")

try:
    result = "5" * 3  # 可以：字串重複
    print(f"字串重複: {result}")
except TypeError as e:
    print(f"錯誤: {e}")

# 顯式型別轉換
num_str = "123"
num_int = int(num_str)      # 顯式轉換為整數
num_float = float(num_str)  # 顯式轉換為浮點數
bool_val = bool(num_str)    # 顯式轉換為布林值

print(f"轉換結果: {num_int}, {num_float}, {bool_val}")

# 型別檢查函數
print(f"是整數: {isinstance(number, int)}")
print(f"是字串: {isinstance(text, str)}")
print(f"型別名稱: {type(number).__name__}")
```

```javascript !! js
// JavaScript：弱型別動態語言
// 允許隱式型別轉換（型別強制轉換）

// 基本型別
const number = 42;
const text = "Hello";
const flag = true;
const empty = null;
let undefinedVal;

console.log(`數字型別: ${typeof number}`);
console.log(`字串型別: ${typeof text}`);
console.log(`布林型別: ${typeof flag}`);
console.log(`Null 型別: ${typeof empty}`);  // 回傳 "object" (著名的 JS 怪異行為)
console.log(`Undefined 型別: ${typeof undefinedVal}`);

// 自動型別強制轉換
const result1 = "5" + 3;    // "53" (數字轉換為字串)
const result2 = "5" - 3;    // 2 (字串轉換為數字)
const result3 = "5" * 3;    // 15 (字串轉換為數字)

console.log(`字串連接: ${result1}`);
console.log(`減法: ${result2}`);
console.log(`乘法: ${result3}`);

// 顯式型別轉換
const numStr = "123";
const numInt = parseInt(numStr);       // 顯式轉換為整數
const numFloat = parseFloat(numStr);   // 顯式轉換為浮點數
const boolVal = Boolean(numStr);       // 顯式轉換為布林值

console.log(`轉換結果: ${numInt}, ${numFloat}, ${boolVal}`);

// 型別檢查函數
console.log(`是數字: ${typeof number === 'number'}`);
console.log(`是字串: ${typeof text === 'string'}`);
console.log(`是陣列: ${Array.isArray([])}`);
console.log(`建構函數: ${number.constructor.name}`);
```
</PythonEditor>

### 型別強制轉換規則

<PythonEditor title="型別轉換規則" compare={true}>
```python !! py
# Python：需要顯式型別轉換

# 數字轉字串
num = 42
str_num = str(num)  # 必須顯式轉換
print(f"數字轉字串: '{str_num}'")

# 字串轉數字
str_val = "123"
try:
    int_val = int(str_val)
    float_val = float(str_val)
    print(f"字串轉數字: {int_val}, {float_val}")
except ValueError as e:
    print(f"轉換錯誤: {e}")

# 無效轉換會引發異常
try:
    invalid = int("abc")
except ValueError as e:
    print(f"無效轉換: {e}")

# 布林轉換
print(f"bool(''): {bool('')}")        # False
print(f"bool('hello'): {bool('hello')}")  # True
print(f"bool(0): {bool(0)}")          # False
print(f"bool(42): {bool(42)}")        # True
print(f"bool([]): {bool([])}")        # False
print(f"bool([1]): {bool([1])}")      # True

# 比較時不會自動轉換
print(f"42 == '42': {42 == '42'}")    # False (不同型別)
print(f"42 == 42: {42 == 42}")        # True

# 清單連接需要相同型別
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = list1 + list2  # 可以：相同型別
print(f"清單連接: {combined}")

# 這會失敗：
# mixed = [1, 2] + "hello"  # TypeError
```

```javascript !! js
// JavaScript：自動型別強制轉換

// 數字轉字串（自動）
const num = 42;
const strNum = num + "";  // 自動轉換
const explicitStr = String(num);  // 顯式轉換
console.log(`數字轉字串: '${strNum}', '${explicitStr}'`);

// 字串轉數字
const strVal = "123";
const intVal1 = +strVal;           // 一元 + 運算符
const intVal2 = Number(strVal);    // Number 建構函數
const intVal3 = parseInt(strVal);  // parseInt 函數
const floatVal = parseFloat(strVal);

console.log(`字串轉數字: ${intVal1}, ${intVal2}, ${intVal3}, ${floatVal}`);

// 無效轉換回傳 NaN
const invalid = Number("abc");
console.log(`無效轉換: ${invalid}`);  // NaN
console.log(`是 NaN: ${isNaN(invalid)}`);       // true

// 布林轉換（在條件中自動）
console.log(`Boolean(''): ${Boolean('')}`);        // false
console.log(`Boolean('hello'): ${Boolean('hello')}`);  // true
console.log(`Boolean(0): ${Boolean(0)}`);          // false
console.log(`Boolean(42): ${Boolean(42)}`);        // true
console.log(`Boolean([]): ${Boolean([])}`);        // true (陣列總是真值)
console.log(`Boolean(null): ${Boolean(null)}`);    // false

// 比較時會發生型別強制轉換
console.log(`42 == '42': ${42 == '42'}`);    // true (強制轉換)
console.log(`42 === '42': ${42 === '42'}`);  // false (嚴格比較)

// 陣列連接時會發生強制轉換
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = arr1.concat(arr2);  // 可以：相同型別
console.log(`陣列連接: ${combined}`);

// 混合型別連接（變成字串）
const mixed = [1, 2] + "hello";  // "1,2hello"
console.log(`混合連接: ${mixed}`);
```
</PythonEditor>

## 真值性和假值

### 假值比較

<PythonEditor title="假值" compare={true}>
```python !! py
# Python 假值
falsy_values = [
    False,      # 布林假值
    None,       # 空值
    0,          # 零（整數）
    0.0,        # 零（浮點數）
    0j,         # 零（複數）
    "",         # 空字串
    [],         # 空清單
    (),         # 空元組
    {},         # 空字典
    set(),      # 空集合
    frozenset() # 空凍結集合
]

print("Python 假值:")
for value in falsy_values:
    print(f"{repr(value)}: {bool(value)}")

# 所有其他值都是真值
truthy_values = [
    True,
    1,
    -1,
    0.1,
    "hello",
    " ",        # 空格是真值
    [0],        # 包含零的清單是真值
    {"key": None}  # 有鍵的字典是真值
]

print("\nPython 真值:")
for value in truthy_values:
    print(f"{repr(value)}: {bool(value)}")

# 條件使用
def check_value(val):
    if val:
        return f"{repr(val)} 是真值"
    else:
        return f"{repr(val)} 是假值"

test_values = [0, "", [], None, "hello", [1]]
for val in test_values:
    print(check_value(val))
```

```javascript !! js
// JavaScript 假值
const falsyValues = [
    false,      // 布林假值
    null,       // Null 值
    undefined,  // Undefined 值
    0,          // 零
    -0,         // 負零
    0n,         // BigInt 零
    NaN,        // 非數字
    "",         // 空字串
    '',         // 空字串（單引號）
    ``          // 空樣板字面值
];

console.log("JavaScript 假值:");
falsyValues.forEach(value => {
    console.log(`${JSON.stringify(value)}: ${Boolean(value)}`);
});

// 所有其他值都是真值（包括空陣列和空物件！）
const truthyValues = [
    true,
    1,
    -1,
    0.1,
    "hello",
    " ",        // 空格是真值
    [],         // 空陣列是真值！
    {},         // 空物件是真值！
    [0],        // 包含零的陣列是真值
    {key: null} // 有鍵的物件是真值
];

console.log("\nJavaScript 真值:");
truthyValues.forEach(value => {
    console.log(`${JSON.stringify(value)}: ${Boolean(value)}`);
});

// 條件使用
function checkValue(val) {
    if (val) {
        return `${JSON.stringify(val)} 是真值`;
    } else {
        return `${JSON.stringify(val)} 是假值`;
    }
}

const testValues = [0, "", [], null, undefined, "hello", [1], {}];
testValues.forEach(val => {
    console.log(checkValue(val));
});

// 陣列和物件的特殊情況
console.log("\n陣列/物件特殊情況:");
console.log(`[] == false: ${[] == false}`);    // true (強制轉換)
console.log(`[] === false: ${[] === false}`);  // false (嚴格比較)
console.log(`[].length: ${[].length}`);        // 0
console.log(`!![] : ${!![]}`);                 // true (陣列是真值)
```
</PythonEditor>

### 條件邏輯差異

<PythonEditor title="條件邏輯" compare={true}>
```python !! py
# Python 條件模式

# 檢查空集合
def process_data(data_list):
    if not data_list:  # 檢查空清單
        return "沒有資料要處理"
    
    # 處理非空清單
    return f"處理 {len(data_list)} 個項目"

# 測試不同值
test_cases = [[], [1, 2, 3], None]
for case in test_cases:
    try:
        result = process_data(case)
        print(f"輸入: {case} -> {result}")
    except TypeError as e:
        print(f"{case} 錯誤: {e}")

# 檢查 None vs 空值
def safe_operation(value):
    if value is None:
        return "值是 None"
    elif not value:
        return "值是空的但不是 None"
    else:
        return f"值有內容: {value}"

test_values = [None, "", [], 0, "hello"]
for val in test_values:
    print(f"{repr(val)}: {safe_operation(val)}")

# 字典鍵檢查
user_data = {"name": "Alice", "age": None, "email": ""}

if "name" in user_data and user_data["name"]:
    print(f"使用者姓名: {user_data['name']}")

if "age" in user_data and user_data["age"] is not None:
    print(f"使用者年齡: {user_data['age']}")
else:
    print("未提供年齡")

# 預設值模式
def get_setting(config, key, default=None):
    return config.get(key) or default

config = {"debug": False, "timeout": 0, "name": ""}
print(f"除錯: {get_setting(config, 'debug', True)}")
print(f"超時: {get_setting(config, 'timeout', 30)}")
print(f"名稱: {get_setting(config, 'name', 'Default')}")
```

```javascript !! js
// JavaScript 條件模式

// 檢查空集合
function processData(dataList) {
    // 必須明確檢查 null/undefined 和長度
    if (!dataList || dataList.length === 0) {
        return "沒有資料要處理";
    }
    
    return `處理 ${dataList.length} 個項目`;
}

// 測試不同值
const testCases = [[], [1, 2, 3], null, undefined];
testCases.forEach(testCase => {
    try {
        const result = processData(testCase);
        console.log(`輸入: ${JSON.stringify(testCase)} -> ${result}`);
    } catch (error) {
        console.log(`${testCase} 錯誤: ${error.message}`);
    }
});

// 檢查 null/undefined vs 空值
function safeOperation(value) {
    if (value === null) {
        return "值是 null";
    } else if (value === undefined) {
        return "值是 undefined";
    } else if (!value) {
        return "值是假值但不是 null/undefined";
    } else {
        return `值有內容: ${value}`;
    }
}

const testValues = [null, undefined, "", [], 0, "hello"];
testValues.forEach(val => {
    console.log(`${JSON.stringify(val)}: ${safeOperation(val)}`);
});

// 物件屬性檢查
const userData = {name: "Alice", age: null, email: ""};

if (userData.name && userData.name.length > 0) {
    console.log(`使用者姓名: ${userData.name}`);
}

if (userData.hasOwnProperty('age') && userData.age !== null) {
    console.log(`使用者年齡: ${userData.age}`);
} else {
    console.log("未提供年齡");
}

// 預設值模式（多種方法）
function getSetting(config, key, defaultValue = null) {
    // 方法 1：使用邏輯 OR（注意假值）
    return config[key] || defaultValue;
}

function getSettingSafe(config, key, defaultValue = null) {
    // 方法 2：空值合併運算符（ES2020）
    return config[key] ?? defaultValue;
}

const config = {debug: false, timeout: 0, name: ""};
console.log(`除錯 (OR): ${getSetting(config, 'debug', true)}`);      // true (錯誤！)
console.log(`除錯 (??): ${getSettingSafe(config, 'debug', true)}`);  // false (正確)
console.log(`超時 (OR): ${getSetting(config, 'timeout', 30)}`);    // 30 (錯誤！)
console.log(`超時 (??): ${getSettingSafe(config, 'timeout', 30)}`); // 0 (正確)
console.log(`名稱 (OR): ${getSetting(config, 'name', 'Default')}`);   // "Default"
console.log(`名稱 (??): ${getSettingSafe(config, 'name', 'Default')}`); // ""
```
</PythonEditor>

## 型別檢查和驗證

### 執行時型別檢查

<PythonEditor title="型別檢查方法" compare={true}>
```python !! py
# Python 型別檢查

import types
from typing import Union, List, Dict, Any

def comprehensive_type_check(value):
    """Python 中的全面型別檢查"""
    
    # 基本型別檢查
    print(f"值: {repr(value)}")
    print(f"型別: {type(value)}")
    print(f"型別名稱: {type(value).__name__}")
    
    # isinstance 檢查
    print(f"是整數: {isinstance(value, int)}")
    print(f"是字串: {isinstance(value, str)}")
    print(f"是清單: {isinstance(value, list)}")
    print(f"是字典: {isinstance(value, dict)}")
    
    # 多重型別檢查
    print(f"是數字: {isinstance(value, (int, float))}")
    print(f"可迭代: {hasattr(value, '__iter__')}")
    print(f"可呼叫: {callable(value)}")
    
    # 鴨子型別檢查
    print(f"有長度: {hasattr(value, '__len__')}")
    print(f"有鍵: {hasattr(value, 'keys')}")
    print(f"有追加: {hasattr(value, 'append')}")
    
    print("-" * 40)

# 測試不同型別
test_values = [
    42,
    "hello",
    [1, 2, 3],
    {"key": "value"},
    None,
    lambda x: x,
    set([1, 2, 3])
]

for val in test_values:
    comprehensive_type_check(val)

# 型別驗證函數
def validate_user_data(data):
    """使用適當型別檢查驗證使用者資料"""
    
    if not isinstance(data, dict):
        raise TypeError("資料必須是字典")
    
    required_fields = {
        'name': str,
        'age': int,
        'email': str
    }
    
    for field, expected_type in required_fields.items():
        if field not in data:
            raise ValueError(f"缺少必要欄位: {field}")
        
        if not isinstance(data[field], expected_type):
            raise TypeError(f"欄位 '{field}' 必須是 {expected_type.__name__} 型別")
        
        if expected_type == str and not data[field].strip():
            raise ValueError(f"欄位 '{field}' 不能為空")
        
        if expected_type == int and data[field] < 0:
            raise ValueError(f"欄位 '{field}' 必須是非負數")
    
    return True

# 測試驗證
valid_data = {"name": "Alice", "age": 25, "email": "alice@example.com"}
invalid_data = {"name": "", "age": -5, "email": 123}

try:
    validate_user_data(valid_data)
    print("有效資料通過驗證")
except (TypeError, ValueError) as e:
    print(f"驗證錯誤: {e}")

try:
    validate_user_data(invalid_data)
except (TypeError, ValueError) as e:
    print(f"無效資料驗證失敗: {e}")
```

```javascript !! js
// JavaScript 型別檢查

function comprehensiveTypeCheck(value) {
    // 基本型別檢查
    console.log(`值: ${JSON.stringify(value)}`);
    console.log(`型別: ${typeof value}`);
    console.log(`建構函數: ${value?.constructor?.name || 'N/A'}`);
    
    // 特定型別檢查
    console.log(`是數字: ${typeof value === 'number'}`);
    console.log(`是字串: ${typeof value === 'string'}`);
    console.log(`是布林: ${typeof value === 'boolean'}`);
    console.log(`是物件: ${typeof value === 'object'}`);
    console.log(`是函數: ${typeof value === 'function'}`);
    
    // 更具體的物件型別檢查
    console.log(`是 null: ${value === null}`);
    console.log(`是 undefined: ${value === undefined}`);
    console.log(`是陣列: ${Array.isArray(value)}`);
    console.log(`是日期: ${value instanceof Date}`);
    console.log(`是正規表達式: ${value instanceof RegExp}`);
    
    // 鴨子型別檢查
    console.log(`有長度: ${value && typeof value.length === 'number'}`);
    console.log(`有鍵方法: ${value && typeof value.keys === 'function'}`);
    console.log(`有推送方法: ${value && typeof value.push === 'function'}`);
    console.log(`可迭代: ${value && typeof value[Symbol.iterator] === 'function'}`);
    
    console.log("-".repeat(40));
}

// 測試不同型別
const testValues = [
    42,
    "hello",
    [1, 2, 3],
    {key: "value"},
    null,
    undefined,
    function() {},
    new Date(),
    /regex/
];

testValues.forEach(val => {
    comprehensiveTypeCheck(val);
});

// 型別驗證函數
function validateUserData(data) {
    // 檢查資料是否為物件
    if (typeof data !== 'object' || data === null || Array.isArray(data)) {
        throw new TypeError("資料必須是普通物件");
    }
    
    const requiredFields = {
        name: 'string',
        age: 'number',
        email: 'string'
    };
    
    for (const [field, expectedType] of Object.entries(requiredFields)) {
        if (!(field in data)) {
            throw new Error(`缺少必要欄位: ${field}`);
        }
        
        if (typeof data[field] !== expectedType) {
            throw new TypeError(`欄位 '${field}' 必須是 ${expectedType} 型別`);
        }
        
        if (expectedType === 'string' && !data[field].trim()) {
            throw new Error(`欄位 '${field}' 不能為空`);
        }
        
        if (expectedType === 'number' && (data[field] < 0 || !Number.isFinite(data[field]))) {
            throw new Error(`欄位 '${field}' 必須是非負的有限數字`);
        }
    }
    
    return true;
}

// 進階型別檢查工具
class TypeChecker {
    static isInteger(value) {
        return Number.isInteger(value);
    }
    
    static isFloat(value) {
        return typeof value === 'number' && !Number.isInteger(value);
    }
    
    static isEmptyObject(value) {
        return typeof value === 'object' && 
               value !== null && 
               !Array.isArray(value) && 
               Object.keys(value).length === 0;
    }
    
    static isEmptyArray(value) {
        return Array.isArray(value) && value.length === 0;
    }
    
    static isPrimitive(value) {
        return value !== Object(value);
    }
}

// 測試驗證
const validData = {name: "Alice", age: 25, email: "alice@example.com"};
const invalidData = {name: "", age: -5, email: 123};

try {
    validateUserData(validData);
    console.log("有效資料通過驗證");
} catch (error) {
    console.log(`驗證錯誤: ${error.message}`);
}

try {
    validateUserData(invalidData);
} catch (error) {
    console.log(`無效資料驗證失敗: ${error.message}`);
}

// 測試工具函數
console.log(`42 是整數: ${TypeChecker.isInteger(42)}`);
console.log(`3.14 是浮點數: ${TypeChecker.isFloat(3.14)}`);
console.log(`{} 是空物件: ${TypeChecker.isEmptyObject({})}`);
console.log(`[] 是空陣列: ${TypeChecker.isEmptyArray([])}`);
console.log(`"hello" 是基本型別: ${TypeChecker.isPrimitive("hello")}`);
```
</PythonEditor>

## Null 和 Undefined 處理

### None vs Null vs Undefined

<PythonEditor title="空值處理" compare={true}>
```python !! py
# Python：只有 None 代表空值

def analyze_none_handling():
    # Python 只有 None
    value = None
    
    print(f"None 值: {value}")
    print(f"None 型別: {type(value)}")
    print(f"None is None: {value is None}")
    print(f"None == None: {value == None}")  # 可以但不推薦
    print(f"bool(None): {bool(None)}")
    
    # 預設參數處理
    def greet(name=None):
        if name is None:
            return "你好，匿名使用者！"
        return f"你好，{name}！"
    
    print(f"無參數: {greet()}")
    print(f"有參數: {greet('Alice')}")
    print(f"明確 None: {greet(None)}")
    
    # 可選返回值
    def find_user(user_id):
        users = {1: "Alice", 2: "Bob"}
        return users.get(user_id)  # 如果找不到返回 None
    
    user = find_user(3)
    if user is None:
        print("找不到使用者")
    else:
        print(f"找到使用者: {user}")
    
    # 包含 None 值的字典
    data = {
        "name": "Alice",
        "age": None,  # 明確設為 None
        "city": "New York"
    }
    
    for key, value in data.items():
        if value is None:
            print(f"{key} 未設定")
        else:
            print(f"{key}: {value}")

analyze_none_handling()

# 集合中的 None
def process_values(values):
    """處理可能包含 None 值的清單"""
    valid_values = [v for v in values if v is not None]
    none_count = len(values) - len(valid_values)
    
    print(f"總值數: {len(values)}")
    print(f"有效值數: {len(valid_values)}")
    print(f"None 值數: {none_count}")
    
    return valid_values

test_list = [1, None, 3, None, 5]
result = process_values(test_list)
print(f"處理結果: {result}")
```

```javascript !! js
// JavaScript：既有 null 也有 undefined

function analyzeNullUndefinedHandling() {
    // JavaScript 有 null 和 undefined
    const nullValue = null;
    let undefinedValue;  // 預設為 undefined
    const explicitUndefined = undefined;
    
    console.log(`Null 值: ${nullValue}`);
    console.log(`Undefined 值: ${undefinedValue}`);
    console.log(`Null 型別: ${typeof nullValue}`);       // "object" (怪異行為)
    console.log(`Undefined 型別: ${typeof undefinedValue}`); // "undefined"
    
    // 相等比較
    console.log(`null === null: ${null === null}`);
    console.log(`undefined === undefined: ${undefined === undefined}`);
    console.log(`null === undefined: ${null === undefined}`);  // false
    console.log(`null == undefined: ${null == undefined}`);    // true (強制轉換)
    
    // 布林轉換
    console.log(`Boolean(null): ${Boolean(null)}`);
    console.log(`Boolean(undefined): ${Boolean(undefined)}`);
    
    // 預設參數處理
    function greet(name = "匿名使用者") {
        // ES6 預設值只對 undefined 觸發，不對 null
        return `你好，${name}！`;
    }
    
    console.log(`無參數: ${greet()}`);
    console.log(`Undefined 參數: ${greet(undefined)}`);
    console.log(`Null 參數: ${greet(null)}`);  // "你好，null！"
    
    // 更好的預設處理
    function greetSafe(name) {
        const safeName = name ?? "匿名使用者";  // 空值合併
        return `你好，${safeName}！`;
    }
    
    console.log(`安全 - 無參數: ${greetSafe()}`);
    console.log(`安全 - undefined: ${greetSafe(undefined)}`);
    console.log(`安全 - null: ${greetSafe(null)}`);
    
    // 可選返回值
    function findUser(userId) {
        const users = {1: "Alice", 2: "Bob"};
        return users[userId];  // 如果找不到返回 undefined
    }
    
    const user = findUser(3);
    if (user === undefined) {
        console.log("找不到使用者");
    } else {
        console.log(`找到使用者: ${user}`);
    }
    
    // 包含 null/undefined 值的物件
    const data = {
        name: "Alice",
        age: null,        // 明確設為 null
        city: "New York"
        // email 是 undefined（不存在）
    };
    
    for (const [key, value] of Object.entries(data)) {
        if (value === null) {
            console.log(`${key} 明確為 null`);
        } else if (value === undefined) {
            console.log(`${key} 是 undefined`);
        } else {
            console.log(`${key}: ${value}`);
        }
    }
    
    // 檢查屬性是否存在
    console.log(`有 name 屬性: ${'name' in data}`);
    console.log(`有 email 屬性: ${'email' in data}`);
    console.log(`Name 值: ${data.name}`);
    console.log(`Email 值: ${data.email}`);  // undefined
}

analyzeNullUndefinedHandling();

// 陣列中的 null/undefined
function processValues(values) {
    // 過濾掉 null 和 undefined
    const validValues = values.filter(v => v != null);  // 同時過濾 null 和 undefined
    const nullCount = values.filter(v => v === null).length;
    const undefinedCount = values.filter(v => v === undefined).length;
    
    console.log(`總值數: ${values.length}`);
    console.log(`有效值數: ${validValues.length}`);
    console.log(`Null 值數: ${nullCount}`);
    console.log(`Undefined 值數: ${undefinedCount}`);
    
    return validValues;
}

const testArray = [1, null, 3, undefined, 5];
const result = processValues(testArray);
console.log(`處理結果: ${result}`);

// 選擇性鏈接（ES2020）
const user = {
    name: "Alice",
    address: {
        street: "123 Main St",
        city: "New York"
    }
};

const userWithoutAddress = {
    name: "Bob"
};

console.log(`Alice 的城市: ${user.address?.city}`);           // "New York"
console.log(`Bob 的城市: ${userWithoutAddress.address?.city}`); // undefined
console.log(`巢狀存取: ${user.address?.country?.code}`);   // undefined
```
</PythonEditor>

## 常見型別相關陷阱

### 避免常見錯誤

<PythonEditor title="常見陷阱" compare={true}>
```python !! py
# Python 型別相關陷阱和解決方案

# 陷阱 1：可變預設參數
def bad_function(items=[]):  # 錯誤：可變預設值
    items.append("新項目")
    return items

def good_function(items=None):  # 正確：使用 None
    if items is None:
        items = []
    items.append("新項目")
    return items

# 測試差異
print("錯誤函數:")
print(bad_function())      # ['新項目']
print(bad_function())      # ['新項目', '新項目'] - 共享狀態！

print("\n正確函數:")
print(good_function())     # ['新項目']
print(good_function())     # ['新項目'] - 每次都是新清單

# 陷阱 2：延遲綁定閉包
def create_functions_bad():
    functions = []
    for i in range(3):
        functions.append(lambda: i)  # 錯誤：延遲綁定
    return functions

def create_functions_good():
    functions = []
    for i in range(3):
        functions.append(lambda x=i: x)  # 正確：預設參數
    return functions

print("\n延遲綁定問題:")
bad_funcs = create_functions_bad()
for func in bad_funcs:
    print(func())  # 全部印出 2！

print("\n修正延遲綁定:")
good_funcs = create_functions_good()
for func in good_funcs:
    print(func())  # 印出 0, 1, 2

# 陷阱 3：Python 3 中的整數除法變化
def division_examples():
    # Python 3 行為
    print(f"7 / 2 = {7 / 2}")      # 3.5 (真除法)
    print(f"7 // 2 = {7 // 2}")    # 3 (地板除法)
    
    # 明確處理整數除法
    def safe_divide(a, b):
        if b == 0:
            raise ValueError("不能除以零")
        return a / b
    
    try:
        result = safe_divide(7, 2)
        print(f"安全除法: {result}")
    except ValueError as e:
        print(f"除法錯誤: {e}")

division_examples()

# 陷阱 4：字串格式化型別問題
def formatting_issues():
    # 小心格式化中的 None 值
    name = None
    age = 25
    
    # 這樣可以但可能不是你想要的
    print(f"姓名: {name}, 年齡: {age}")  # "姓名: None, 年齡: 25"
    
    # 更好的方法
    safe_name = name or "未知"
    print(f"姓名: {safe_name}, 年齡: {age}")  # "姓名: 未知, 年齡: 25"

formatting_issues()
```

```javascript !! js
// JavaScript 型別相關陷阱和解決方案

// 陷阱 1：比較中的型別強制轉換
function comparisonPitfalls() {
    console.log("比較陷阱:");
    
    // 令人驚訝的相等結果
    console.log(`"" == false: ${"" == false}`);        // true
    console.log(`0 == false: ${0 == false}`);          // true
    console.log(`[] == false: ${[] == false}`);        // true
    console.log(`"0" == false: ${"0" == false}`);      // true
    console.log(`null == undefined: ${null == undefined}`); // true
    
    // 總是使用嚴格相等
    console.log(`"" === false: ${"" === false}`);      // false
    console.log(`0 === false: ${0 === false}`);        // false
    console.log(`[] === false: ${[] === false}`);      // false
    console.log(`null === undefined: ${null === undefined}`); // false
}

comparisonPitfalls();

// 陷阱 2：陣列檢測
function arrayDetection() {
    console.log("\n陣列檢測陷阱:");
    
    const arr = [1, 2, 3];
    
    // 錯誤的陣列檢查方式
    console.log(`typeof []: ${typeof arr}`);           // "object" - 沒有幫助
    console.log(`arr instanceof Array: ${arr instanceof Array}`); // true，但在框架間可能失敗
    
    // 正確方式
    console.log(`Array.isArray([]): ${Array.isArray(arr)}`); // true - 可靠
}

arrayDetection();

// 陷阱 3：浮點數精度
function floatingPointIssues() {
    console.log("\n浮點數陷阱:");
    
    const result = 0.1 + 0.2;
    console.log(`0.1 + 0.2 = ${result}`);              // 0.30000000000000004
    console.log(`0.1 + 0.2 === 0.3: ${result === 0.3}`); // false
    
    // 解決方案：使用 epsilon 比較
    function isEqual(a, b, epsilon = Number.EPSILON) {
        return Math.abs(a - b) < epsilon;
    }
    
    console.log(`使用 epsilon 相等: ${isEqual(result, 0.3)}`); // true
    
    // 或者對於貨幣，以分為單位計算
    const price1 = 10; // 10 分
    const price2 = 20; // 20 分
    const total = price1 + price2; // 30 分
    console.log(`價格總計: $${total / 100}`); // $0.30
}

floatingPointIssues();

// 陷阱 4：NaN 行為
function nanPitfalls() {
    console.log("\nNaN 陷阱:");
    
    const notANumber = Number("abc");
    console.log(`Number("abc"): ${notANumber}`);        // NaN
    console.log(`NaN === NaN: ${NaN === NaN}`);         // false!
    console.log(`notANumber === notANumber: ${notANumber === notANumber}`); // false!
    
    // 正確檢查 NaN 的方式
    console.log(`isNaN(notANumber): ${isNaN(notANumber)}`);     // true
    console.log(`Number.isNaN(notANumber): ${Number.isNaN(notANumber)}`); // true (更可靠)
    
    // isNaN 會強制轉換，Number.isNaN 不會
    console.log(`isNaN("abc"): ${isNaN("abc")}`);           // true (強制轉換)
    console.log(`Number.isNaN("abc"): ${Number.isNaN("abc")}`); // false (無強制轉換)
}

nanPitfalls();

// 陷阱 5：提升和暫時性死區
function hoistingIssues() {
    console.log("\n提升陷阱:");
    
    // var 提升（避免使用）
    console.log(`宣告前的 varVariable: ${typeof varVariable}`); // "undefined"
    var varVariable = "我被提升了";
    
    // let/const 暫時性死區
    try {
        console.log(letVariable); // ReferenceError
        let letVariable = "我沒有被提升";
    } catch (error) {
        console.log(`Let 錯誤: ${error.message}`);
    }
    
    // 函數提升
    console.log(`提升的函數: ${hoistedFunction()}`); // 可以執行
    
    function hoistedFunction() {
        return "我也被提升了";
    }
    
    // 函數表達式不會提升
    try {
        console.log(notHoisted()); // TypeError
    } catch (error) {
        console.log(`函數表達式錯誤: ${error.message}`);
    }
    
    const notHoisted = function() {
        return "我沒有被提升";
    };
}

hoistingIssues();

// 陷阱 6：物件屬性存取
function propertyAccessPitfalls() {
    console.log("\n屬性存取陷阱:");
    
    const obj = {
        "normal-key": "value1",
        "123": "value2",
        "": "value3"
    };
    
    // 點記法限制
    // console.log(obj.normal-key);    // SyntaxError
    // console.log(obj.123);           // SyntaxError
    
    // 對於特殊鍵使用括號記法
    console.log(`obj["normal-key"]: ${obj["normal-key"]}`);
    console.log(`obj["123"]: ${obj["123"]}`);
    console.log(`obj[""]: ${obj[""]}`);
    
    // 安全屬性存取
    const userData = {name: "Alice"};
    console.log(`安全存取: ${userData.age?.toString() || "未提供"}`);
    
    // 使用選擇性鏈接和空值合併
    const config = {
        database: {
            host: "localhost"
            // 缺少 port
        }
    };
    
    const port = config.database?.port ?? 5432;
    console.log(`資料庫埠: ${port}`);
}

propertyAccessPitfalls();
```
</PythonEditor>

## 型別安全最佳實踐

### 撰寫型別安全的程式碼

<PythonEditor title="型別安全最佳實踐" compare={true}>
```python !! py
# Python 型別安全最佳實踐

from typing import Optional, Union, List, Dict, Any
from dataclasses import dataclass

# 使用型別提示以獲得更好的程式碼文件
def calculate_total(prices: List[float], tax_rate: float = 0.1) -> float:
    """計算包含稅的總價。"""
    if not prices:
        return 0.0
    
    subtotal = sum(prices)
    return subtotal * (1 + tax_rate)

# 使用 dataclass 處理結構化資料
@dataclass
class User:
    name: str
    age: int
    email: Optional[str] = None
    
    def __post_init__(self):
        if self.age < 0:
            raise ValueError("年齡不能為負數")
        if not self.name.strip():
            raise ValueError("姓名不能為空")

# 輸入驗證與型別檢查
def process_user_input(data: Dict[str, Any]) -> User:
    """處理和驗證使用者輸入。"""
    
    # 驗證必要欄位
    required_fields = ['name', 'age']
    for field in required_fields:
        if field not in data:
            raise ValueError(f"缺少必要欄位: {field}")
    
    # 型別驗證
    if not isinstance(data['name'], str):
        raise TypeError("姓名必須是字串")
    
    if not isinstance(data['age'], int):
        raise TypeError("年齡必須是整數")
    
    # 可選欄位驗證
    email = data.get('email')
    if email is not None and not isinstance(email, str):
        raise TypeError("電子郵件必須是字串")
    
    return User(
        name=data['name'],
        age=data['age'],
        email=email
    )

# 安全型別轉換
def safe_int_conversion(value: Any) -> Optional[int]:
    """安全地將值轉換為整數。"""
    if isinstance(value, int):
        return value
    
    if isinstance(value, str):
        try:
            return int(value)
        except ValueError:
            return None
    
    if isinstance(value, float):
        if value.is_integer():
            return int(value)
        return None
    
    return None

# 測試函數
try:
    user_data = {"name": "Alice", "age": 25, "email": "alice@example.com"}
    user = process_user_input(user_data)
    print(f"建立使用者: {user}")
    
    prices = [10.99, 5.50, 3.25]
    total = calculate_total(prices)
    print(f"總價: ${total:.2f}")
    
    # 測試安全轉換
    test_values = ["123", 45.0, "abc", 3.14]
    for val in test_values:
        converted = safe_int_conversion(val)
        print(f"{val} -> {converted}")
        
except (ValueError, TypeError) as e:
    print(f"錯誤: {e}")
```

```javascript !! js
// JavaScript 型別安全最佳實踐

// 使用 TypeScript 風格的 JSDoc 註解進行型別文件化
/**
 * 計算包含稅的總價
 * @param {number[]} prices - 價格陣列
 * @param {number} taxRate - 稅率（預設 0.1）
 * @returns {number} 含稅總價
 */
function calculateTotal(prices, taxRate = 0.1) {
    // 輸入驗證
    if (!Array.isArray(prices)) {
        throw new TypeError("價格必須是陣列");
    }
    
    if (typeof taxRate !== 'number' || taxRate < 0) {
        throw new TypeError("稅率必須是非負數");
    }
    
    if (prices.length === 0) {
        return 0;
    }
    
    // 驗證所有價格都是數字
    for (const price of prices) {
        if (typeof price !== 'number' || !Number.isFinite(price)) {
            throw new TypeError("所有價格必須是有限數字");
        }
    }
    
    const subtotal = prices.reduce((sum, price) => sum + price, 0);
    return subtotal * (1 + taxRate);
}

// 使用類別處理結構化資料並驗證
class User {
    /**
     * @param {string} name - 使用者姓名
     * @param {number} age - 使用者年齡
     * @param {string|null} email - 使用者電子郵件（可選）
     */
    constructor(name, age, email = null) {
        this.setName(name);
        this.setAge(age);
        this.setEmail(email);
    }
    
    setName(name) {
        if (typeof name !== 'string') {
            throw new TypeError("姓名必須是字串");
        }
        if (!name.trim()) {
            throw new Error("姓名不能為空");
        }
        this.name = name;
    }
    
    setAge(age) {
        if (!Number.isInteger(age)) {
            throw new TypeError("年齡必須是整數");
        }
        if (age < 0) {
            throw new Error("年齡不能為負數");
        }
        this.age = age;
    }
    
    setEmail(email) {
        if (email !== null && typeof email !== 'string') {
            throw new TypeError("電子郵件必須是字串或 null");
        }
        this.email = email;
    }
    
    toJSON() {
        return {
            name: this.name,
            age: this.age,
            email: this.email
        };
    }
}

// 輸入驗證工具
class InputValidator {
    static validateUserData(data) {
        if (typeof data !== 'object' || data === null || Array.isArray(data)) {
            throw new TypeError("資料必須是普通物件");
        }
        
        const requiredFields = ['name', 'age'];
        for (const field of requiredFields) {
            if (!(field in data)) {
                throw new Error(`缺少必要欄位: ${field}`);
            }
        }
        
        return new User(data.name, data.age, data.email || null);
    }
    
    static isValidEmail(email) {
        if (typeof email !== 'string') return false;
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        return emailRegex.test(email);
    }
}

// 安全型別轉換工具
class TypeConverter {
    static toSafeInteger(value) {
        if (Number.isInteger(value)) {
            return value;
        }
        
        if (typeof value === 'string') {
            const parsed = parseInt(value, 10);
            return Number.isNaN(parsed) ? null : parsed;
        }
        
        if (typeof value === 'number' && Number.isFinite(value)) {
            return Number.isInteger(value) ? value : Math.floor(value);
        }
        
        return null;
    }
    
    static toSafeFloat(value) {
        if (typeof value === 'number' && Number.isFinite(value)) {
            return value;
        }
        
        if (typeof value === 'string') {
            const parsed = parseFloat(value);
            return Number.isNaN(parsed) ? null : parsed;
        }
        
        return null;
    }
    
    static toSafeString(value) {
        if (typeof value === 'string') {
            return value;
        }
        
        if (value === null || value === undefined) {
            return null;
        }
        
        return String(value);
    }
}

// 執行時型別檢查工具
class TypeChecker {
    static assertType(value, expectedType, fieldName = 'value') {
        const actualType = typeof value;
        if (actualType !== expectedType) {
            throw new TypeError(`${fieldName} 必須是 ${expectedType}，得到 ${actualType}`);
        }
    }
    
    static assertArray(value, fieldName = 'value') {
        if (!Array.isArray(value)) {
            throw new TypeError(`${fieldName} 必須是陣列`);
        }
    }
    
    static assertInstanceOf(value, constructor, fieldName = 'value') {
        if (!(value instanceof constructor)) {
            throw new TypeError(`${fieldName} 必須是 ${constructor.name} 的實例`);
        }
    }
}

// 測試函數
try {
    const userData = {name: "Alice", age: 25, email: "alice@example.com"};
    const user = InputValidator.validateUserData(userData);
    console.log(`建立使用者: ${JSON.stringify(user)}`);
    
    const prices = [10.99, 5.50, 3.25];
    const total = calculateTotal(prices);
    console.log(`總價: $${total.toFixed(2)}`);
    
    // 測試安全轉換
    const testValues = ["123", 45.0, "abc", 3.14, null];
    testValues.forEach(val => {
        const converted = TypeConverter.toSafeInteger(val);
        console.log(`${JSON.stringify(val)} -> ${converted}`);
    });
    
    // 型別斷言
    TypeChecker.assertType("hello", "string", "問候語");
    TypeChecker.assertArray([1, 2, 3], "數字");
    console.log("所有型別檢查都通過");
    
} catch (error) {
    console.log(`錯誤: ${error.message}`);
}

// 現代 JavaScript 型別安全功能
class ModernTypeSafety {
    // 使用選擇性鏈接和空值合併
    static safePropertyAccess(obj, path) {
        // 安全的巢狀屬性存取
        return obj?.user?.profile?.name ?? '未知';
    }
    
    // 使用解構與預設值
    static processConfig({host = 'localhost', port = 3000, ssl = false} = {}) {
        return {host, port, ssl};
    }
    
    // 使用 Map 以獲得比物件更好的型別安全
    static createTypedMap() {
        const userMap = new Map();
        userMap.set('alice', {name: 'Alice', age: 25});
        userMap.set('bob', {name: 'Bob', age: 30});
        return userMap;
    }
}

// 測試現代功能
const config = ModernTypeSafety.processConfig({host: 'example.com'});
console.log(`設定: ${JSON.stringify(config)}`);

const userMap = ModernTypeSafety.createTypedMap();
console.log(`使用者映射大小: ${userMap.size}`);
```
</PythonEditor>

## 總結

本模組涵蓋了 Python 和 JavaScript 動態型別系統之間的關鍵差異：

### 主要要點：

1. **型別系統哲學**: Python 是強型別（顯式轉換），JavaScript 是弱型別（自動強制轉換）
2. **假值**: 不同規則 - JavaScript 有更多假值，包括空陣列為真值
3. **空值處理**: Python 只有 `None`，JavaScript 有 `null` 和 `undefined`
4. **型別檢查**: 每種語言都有不同的方法和可用工具
5. **常見陷阱**: 理解型別強制轉換、比較運算符和型別驗證

### 最佳實踐：
- 在 JavaScript 中總是使用嚴格相等（`===`）
- 在兩種語言中都明確驗證輸入
- 在 Python 中使用型別提示，考慮在 JavaScript 中使用 TypeScript
- 注意 JavaScript 中的自動型別轉換
- 使用現代 JavaScript 功能，如選擇性鏈接和空值合併

理解這些型別系統差異對於從 Python 轉換到 JavaScript 時撰寫穩健程式碼至關重要。下一個模組將詳細探討函數定義和範圍機制。
